package com.ctbri.JWLetter.dao.neo4j.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Repository;

import com.alibaba.fastjson.util.TypeUtils;
import com.ctbri.JWLetter.bean.Link;
import com.ctbri.JWLetter.bean.Node;
import com.ctbri.JWLetter.dao.neo4j.NodeDao;
import com.ctbri.JWLetter.frame.NeoDataPooledConnection;

/**
 * Neo4j下节点数据层实现
 * 
 * @author Hogan
 *
 */
@Repository
public class NodeDaoImpl implements NodeDao {
	
	private Logger log = Logger.getLogger(getClass());
	
	@Resource
	private NeoDataPooledConnection neoDataPooledConnection;

	@SuppressWarnings("unchecked")
	@Override
	public Map<String, Object> findNodesByWord(String word) {
		Connection connection = neoDataPooledConnection.getCurrentConnecton();
		Map<String, Object> result = new HashMap<String, Object>();
		Set<Integer> nodeIdMap = new HashSet<Integer>();
		List<Node> nodes=null;
		List<Link> links=null;
		String query = "MATCH  (n{content:'"
                + word
                + "'})-[r]->(node1:person) "
                + "RETURN n as node, r as dis, node1 as nextlayer "
                + "UNION "
                + "MATCH (n{content:'"
                + word
                + "'} )-[r]->(node1) "
                + "WHERE node1.category = 'institution' OR node1.category = 'location' "
                + "RETURN  n as node,r as dis, node1 as nextlayer "
                + "ORDER by r.times DESC limit 20 "
                + "UNION "
                + "MATCH (n{content:'"
                + word
                + "'} )-[r]->(node1) "
                + "WHERE node1.category = 'institution' OR node1.category = 'location' "
                + "WITH  node1 as layer1 "
                + "ORDER by r.times DESC limit 20 "
                + "MATCH (layer1)-[r]->(node2:person) "
                + "WITH layer1,node2 "
                + "ORDER BY r.times DESC "
                + "WITH layer1,collect(node2)[0..5] as list "
                + "ORDER BY id(layer1) "
                + "MATCH (layer1)-[r]->(layer2) "
                + "WHERE layer2 in list "
                + "RETURN layer1 as node, r as dis, layer2 as nextlayer";
		PreparedStatement statement = null;
		ResultSet rs = null;
		try {
			statement = connection.prepareStatement(query);
			rs = statement.executeQuery();
			nodes = new ArrayList<Node>();
			links = new ArrayList<Link>();
			Node center = new Node();
            center.setCategory("person");
            center.setValue(10);
            center.setName(word.toLowerCase());
            nodes.add(center);
			while (rs.next()) {
				LinkedHashMap<String, Object> nodeMap = (LinkedHashMap<String, Object>) rs.getObject(1);
				LinkedHashMap<String, Object> lineMap = (LinkedHashMap<String, Object>) rs.getObject(2);
				Link link = new Link();
				link.setSource(TypeUtils.castToString(lineMap.get("from")));
				link.setTarget(TypeUtils.castToString(lineMap.get("to")));
				link.setWeight(TypeUtils.castToInt(lineMap.get("times")));
				link.setLetterIds(castToIntegers(TypeUtils.castToString(nodeMap.get("article"))));
				links.add(link);
				nodeMap = (LinkedHashMap<String, Object>) rs.getObject(3);
				if(!nodeIdMap.contains(TypeUtils.castToInt(nodeMap.get("node")))){
					nodeIdMap.add(TypeUtils.castToInt(nodeMap.get("node")));
					Node targetNode = new Node();
					targetNode.setValue(TypeUtils.castToInt(lineMap.get("times")));
					targetNode.setNodeId(TypeUtils.castToInt(nodeMap.get("node")));
					targetNode.setName(TypeUtils.castToString(nodeMap.get("content")));
					targetNode.setCategory(TypeUtils.castToString(nodeMap.get("category")));
					targetNode.setArticleIds(castToIntegers(TypeUtils.castToString(nodeMap.get("article"))));
					nodes.add(targetNode);
				}
			}
		} catch (Exception e) {
			log.error("Neo4j查询出错！", e);
		}
		result.put("nodes", nodes);
		result.put("links", links);
		neoDataPooledConnection.releaseConn(connection);
		return result;
	}
	
	
	private Integer[] castToIntegers(String source){
		Integer[] result = null;
		if (source != null) {
			String[] temp = source.substring(1, source.length()-1).split(",");
			result = new Integer[temp.length];
			for (int i = 0; i < temp.length; i++) {
				result[i] = TypeUtils.castToInt(temp[i].trim());
			}
		}
		return result;
	}
}
